package com.fit4as.fit
{
	
// Copyright (c) 2002 Cunningham & Cunningham, Inc.
// Released under the terms of the GNU General Public License version 2 or later.

import com.fit4as.fit.TypeAdapter;
import com.fit4as.util.reflect.ClassUtil;
import flash.utils.getDefinitionByName;
import flash.utils.getQualifiedClassName;
import mx.utils.StringUtil;
import com.fit4as.util.reflect.Method;
import com.fit4as.util.reflect.Field;



public class ColumnFixture extends Fixture
{

    protected var columnBindings : Array; /*of TypeAdapter*/
    protected var hasExecuted : Boolean = false;


    // Traversal ////////////////////////////////

    override public function doRows( rows : Parse ) : void 
    {
        bind( rows.parts );
        super.doRows(rows.more);
    }

    override public function doRow(row : Parse) : void {
        hasExecuted = false;
        try {
            reset(); //template method
            super.doRow(row);
            if( !hasExecuted ) execute();

        } catch( e : Error ) {
            exception( row.leaf(), e );
        }
    }
    
 	public function reset() : void {
        // about to process first cell of row
    }

    public function execute() : void {
        // about to process first method call of row
    }
    

    override public function doCell( cell : Parse, column : int) : void 
    {
        var a : TypeAdapter = columnBindings[ column ];
    	trace("ColumnFixture#doCell " + [ cell.body, a != null, cell.text(), a.field != null, a.method != null, a.type ]);
        try {
            var text : String = cell.text();
            if( text == "" ) {
                check( cell, a );
            } else if ( a == null ) {
                ignore( cell );
            } else if ( a.field != null ) {
                a.set( a.parse( text ));
            } else if ( a.method != null ) {
                check( cell, a );
            }
        } catch( e : Error ) {
            //t race("exception " + e );
            exception(cell, e);
        }
    }

    override public function check(... rest) : void {
        var cell : Parse = Parse(rest[ 0 ]);
        var value : * = rest[ 1 ];
    	//t race("ColumnFixture#check " + [ value, cell, cell.text(), hasExecuted ] );
        if ( ! hasExecuted ) {
            try {
                execute();
            } catch ( e : Error ) {
                exception( cell, e );
            }
            hasExecuted = true;
        }
        super.check.apply( this, rest );
    }

   
    // Utility //////////////////////////////////

    protected function bind( heads : Parse ) : void 
    {
        columnBindings = new Array();
        while( heads != null )
        {
            var name : String = heads.text();
            var suffix : String = "()";
            //t race("bind " +[ name, name == "", endsWith( name, suffix ) ]);
            try {
                if (name == "") {
                    columnBindings.push( null );
                } else if( endsWith( name, suffix )) {
                    columnBindings.push( bindMethod( name.substring( 0, name.length - suffix.length )));
                } else {
                    columnBindings.push( bindField( name ));
                }
            }
            catch( e : Error ) {
                exception( heads, e );
            }
            heads = heads.more;
        }
    }

    private function endsWith(s : String, suffix : String) : Boolean
    {
        return s.length >= suffix.length && s.indexOf(suffix) == s.length - suffix.length;
    }


    protected function bindMethod( name : String ) : TypeAdapter {
    	name = camel( name );
    	var method : Method = ClassUtil.getMethod( getTargetClass(), name, new Array());
    	if( method.getReturnType() == Array )
    	{ 
    		method.setComponentType( getComponentType( name ));
    	}
        return TypeAdapter.onMethod( this, method );
    }

    protected function bindField( name : String ) : TypeAdapter {
    	name = camel( name );
    	var field : Field = ClassUtil.getField( getTargetClass(), name );
    	if( field.getType() == Array ) 
    	{
    		field.setComponentType( getComponentType( name ));
    	}
        //t race("bindField " + [ name, ClassUtil.getField( getTargetClass(), camel(name))]);
        return TypeAdapter.onField( this, field );
    }

    public function getTargetClass() : Class
    {
        return ClassUtil.getClass( this );
    }
    
}
}